// Copyright 2011 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * Given a resolve work item, perform the following work:
 *
 *  *  If the work item has no unknown action dependencies, call the user back
 *     and return.
 *
 *  *  If the work item has any dependencies on actions in packages that have
 *     not yet been processed, process those packages and return.
 *
 * Return an array with the following boolean elements:
 *
 *     Element 0:
 *         Whether this item has been completely processed (i.e. the user was
 *         called back).
 *
 *     Element 1:
 *         Whether any progress was made on the item (i.e. the user was called
 *         back or at least one new package was processed).
 *
 * In other words, element 0 says whether the item should be removed from the
 * list of pending work, and if this function returns a false element 1 for
 * every piece of work in the queue, there must be a non-existent action
 * dependency.
 *
 * @param {!flame.internal.ResolveWorkItem} workItem
 *     The item to process.
 *
 * @param {!flame.internal.StringMap} registeredActions
 *     Actions that have previously been registered.
 *
 * @param {!flame.internal.StringSet} packagesProcessed
 *     Packages that have previously been processed.
 *
 * @param {function(string)} processPackage
 *     A function that knows how to load a FLAME file for a given package and
 *     execute its contents.
 *
 * @return {!Array.<boolean>}
 */
flame.internal.processResolveWorkItem =
    function(workItem, registeredActions, packagesProcessed, processPackage) {
  var fi = flame.internal;

  // Make a list of actions that have not yet been resolved for this piece of
  // work.
  function actionNotResolved(name) { return !registeredActions.contains(name); }
  var unresolvedActions = workItem.actionNames.filter(actionNotResolved);

  // If all of its requisite actions have been resolved, call the user back and
  // return.
  if (unresolvedActions.length == 0) {
    var callbackArg = {};
    workItem.actionNames.forEach(
        function(name) {
          callbackArg[name] = registeredActions.get(name);
        });

    workItem.callback(callbackArg);
    return [true, true];
  }

  // Make a list of packages referenced by the item's action dependencies.
  function getPackage(name) { return fi.parseActionName(name).packageName; }
  var packageDependencies = unresolvedActions.map(getPackage);

  // Process each necessary package.
  var madeProgress = false;
  for (var j = 0; j < packageDependencies.length; ++j) {
    var packageName = packageDependencies[j];

    // Skip any package that we've already processed.
    if (packagesProcessed.contains(packageName)) {
      continue;
    }

    processPackage(packageName);
    packagesProcessed.insert(packageName);
    madeProgress = true;
  }

  return [false, madeProgress];
};
